package com.kj.tms.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedList;

/**
 * @ProjectName: tms
 * @Package: com.hongtu.tms.common.util
 * @ClassName: FormulaCalculator
 * @Description: 字符串得运算
 * @Author: [yangruidong]
 * @CreateDate: 2018/1/2 17:16
 * @UpdateUser: [修改者姓名]
 * @UpdateDate: 2018/1/2 17:16
 * @UpdateRemark: [修改原因备注]
 * @Version: 1.0
 * Copyright: 北京宏图天安 Copyright (c) 2018
 */
public class FormulaCalculator {

    private static boolean isRightFormat = true;
    
    Logger logger = LoggerFactory.getLogger(FormulaCalculator.class);
    
    public static BigDecimal getResult(String formula,int scale){
        if(scale==0){
            //默认保留两位
            scale=2;
        }
        BigDecimal returnValue = new BigDecimal("0");
        try{
            returnValue = doAnalysis(formula,scale);
        }catch(NumberFormatException nfe){
            throw new RuntimeException("公式格式有误，请检查:" + formula);
        }catch(Exception e){
            throw new RuntimeException("公式格式有误，请检查:" + e.toString());
        }
        if(!isRightFormat){
            throw new RuntimeException("公式格式有误，请检查:" + formula);
        }
        return returnValue;
    }
    /**
    * @Method      doAnalysis
    * @Description 解析字符串
    * @Author      [yangruidong]
    * @Version     1.0
    * @Param       
    * @Return      
    * @Exception   
    * @Date        2018/1/3 17:51
    */
    private static BigDecimal doAnalysis(String formula,int scale){
        BigDecimal returnValue = new BigDecimal("0");
        LinkedList<Integer> stack = new LinkedList<Integer>();
        int curPos = 0;
        String beforePart = "";
        String afterPart = "";
        String calculator = "";
        isRightFormat = true;
        while(isRightFormat&&(formula.indexOf('(') >= 0||formula.indexOf(')') >= 0)){
            curPos = 0;
            for(char s : formula.toCharArray()){
                if(s == '('){
                    stack.add(curPos);
                }else if(s == ')'){
                    if(stack.size() > 0){
                        beforePart = formula.substring(0, stack.getLast());
                        afterPart = formula.substring(curPos + 1);
                        calculator = formula.substring(stack.getLast() + 1, curPos);
                        formula = beforePart + doCalculation(calculator,scale) + afterPart;
                        stack.clear();
                        break;
                    }else{
                        isRightFormat = false;
                        throw new RuntimeException("有未关闭的右括号");
                    }
                }
                curPos++;
            }
            if(stack.size() > 0){
//                System.out.println("有未关闭的左括号！");
//                break;
                throw new RuntimeException("有未关闭的左括号");
            }
        }
        if(isRightFormat){
            returnValue = doCalculation(formula,scale);
        }
        return returnValue;
    }

    /**
    * @Method      doCalculation
    * @Description 加减乘除运算
    * @Author      [yangruidong]
    * @Version     1.0
    * @Param       
    * @Return      
    * @Exception   
    * @Date        2018/1/3 17:51
    */
    private static BigDecimal doCalculation(String formula,int scale) {
        ArrayList<BigDecimal> values = new ArrayList<BigDecimal>();
        ArrayList<String> operators = new ArrayList<String>();
        int curPos = 0;
        int prePos = 0;
        int minus = 0;
        for (char s : formula.toCharArray()) {
            if ((s == '+' || s == '-' || s == '*' || s == '/') && minus !=0 && minus !=2) {
                values.add(new BigDecimal(formula.substring(prePos, curPos).trim()));
                operators.add("" + s);
                prePos = curPos + 1;
                minus = minus +1;
            }else{
                minus =1;
            }
            curPos++;
        }
        values.add(new BigDecimal(formula.substring(prePos).trim()));
        char op;
        for (curPos = 0; curPos <= operators.size() - 1; curPos++) {
            op = operators.get(curPos).charAt(0);
            switch (op) {
                case '*':
                    values.add(curPos, values.get(curPos).multiply(values.get(curPos + 1)));
                    values.remove(curPos + 1);
                    values.remove(curPos + 1);
                    operators.remove(curPos);
                    curPos = -1;
                    break;
                case '/':
                    values.add(curPos, values.get(curPos) .divide( values.get(curPos + 1),4, BigDecimal.ROUND_HALF_UP));
                    values.remove(curPos + 1);
                    values.remove(curPos + 1);
                    operators.remove(curPos);
                    curPos = -1;
                    break;
            }
        }
        for (curPos = 0; curPos <= operators.size() - 1; curPos++) {
            op = operators.get(curPos).charAt(0);
            switch (op) {
                case '+':
                    values.add(curPos, values.get(curPos).add(values.get(curPos + 1)));
                    values.remove(curPos + 1);
                    values.remove(curPos + 1);
                    operators.remove(curPos);
                    curPos = -1;
                    break;
                case '-':
                    values.add(curPos, values.get(curPos).subtract( values.get(curPos + 1)));
                    values.remove(curPos + 1);
                    values.remove(curPos + 1);
                    operators.remove(curPos);
                    curPos = -1;
                    break;
            }
        }
        //保留两位小数
        return values.get(0).setScale(scale,BigDecimal.ROUND_HALF_UP);
    }

    public static void main(String[] args) {
        System.out.println(FormulaCalculator.getResult("3-(4*5)+5",2));
        System.out.println(FormulaCalculator.getResult("7/3-(-4)",2));
       // System.out.println(FormulaCalculator.getResult("1287763200000-1276272000000")/(3600*24*1000));
    }

}  